package com.mediastory.spsserver.gcm.service.impl;

import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.google.android.gcm.server.Message;
import com.google.android.gcm.server.Message.Builder;
import com.google.android.gcm.server.MulticastResult;
import com.google.android.gcm.server.Sender;
import com.mediastory.spsserver.gcm.dao.GcmDao;
import com.mediastory.spsserver.gcm.domain.Gcm;
import com.mediastory.spsserver.gcm.service.GcmSvc;

/**
 * Gcm SvcImpl
 * @author Jaewon Choi
 *
 */

@Service
@Transactional
public class GcmSvcImpl implements GcmSvc {

	@Autowired
	private MessageSourceAccessor messages;
	
	@Autowired
	GcmDao gcmDao;
	
	public GcmSvcImpl() {
		// TODO Auto-generated constructor stub
	}

	@Override
	public List<Gcm> findbyList(Map<String, Object> condition)
			throws Exception {
		// TODO Auto-generated method stub
		return (List<Gcm>) (gcmDao.SelectList(condition));
	}

	public Map<String, Object> findbyListPaging(Map<String, Object> condition)
			throws Exception {
		// TODO Auto-generated method stub
		Map<String, Object> resultMap = new HashMap<String, Object>();
		resultMap.put("gcmList", (List<Gcm>) (gcmDao.SelectList(condition)));
		resultMap.put("gcmListTotalCnt", (Integer) (gcmDao.SelectListTotalCnt(condition)));
		
		return resultMap;
	}

	@Override
	public Gcm findby(Integer idx) throws Exception {
		// TODO Auto-generated method stub
		return gcmDao.select(idx);
	}
	
	public Gcm findby(Map<String, Object> condition)
			throws Exception {
		// TODO Auto-generated method stub
		
		return gcmDao.select(condition);
	}

	@Override
	public Gcm add(Gcm gcm) throws Exception {
		// TODO Auto-generated method stub
		
		Gcm result = gcmDao.insert(gcm);
		
		//gcm data 등록
		String[] keyList = gcm.getKey();
		String[] dataList = gcm.getData();
		if(keyList != null && dataList != null){
			Map<String, Object> condition = new HashMap<String, Object>();
			condition.put("gcmIdx", gcm.getIdx());
			condition.put("createdId", gcm.getCreatedId());
			condition.put("createdIp", gcm.getCreatedIp());
			
			for(int i=0;i<dataList.length;i++){
				String key = keyList[i];
				String data = dataList[i];
				condition.put("key", key);
				condition.put("data", data);
				gcmDao.insertData(condition);
			}
		}
		
		return result;
	}

	@Override
	public Gcm modify(Gcm gcm) throws Exception {
		// TODO Auto-generated method stub
		
		gcm = gcmDao.update(gcm);
		
		//gcm data 삭제 후 등록
		String[] keyList = gcm.getKey();
		String[] dataList = gcm.getData();
		if(keyList != null && dataList != null){
			Map<String, Object> condition = new HashMap<String, Object>();
			condition.put("gcmIdx", gcm.getIdx());
			
			//삭제
			condition.put("modifiedId", gcm.getModifiedId());
			condition.put("modifiedIp", gcm.getModifiedIp());
			gcmDao.deleteData(condition);
			
			//등록
			condition.put("createdId", gcm.getModifiedId());
			condition.put("createdIp", gcm.getModifiedIp());
			for(int i=0;i<dataList.length;i++){
				String key = keyList[i];
				String data = dataList[i];
				condition.put("key", key);
				condition.put("data", data);
				gcmDao.insertData(condition);
			}
		}
		
		return gcm;
	}

	@Override
	public int remove(Map<String, Object> condition) throws Exception {
		// TODO Auto-generated method stub
		return gcmDao.delete(condition);
	}

	@Override
	public List<Map<String, Object>> findbyListData(
			Map<String, Object> condition) throws Exception {
		// TODO Auto-generated method stub
		return gcmDao.SelectListData(condition);
	}

	@Override
	public Object findbyListDevice(Map<String, Object> condition)
			throws Exception {
		// TODO Auto-generated method stub
		return gcmDao.SelectListDevice(condition);
	}

	@Override
	public int addDevice(Map<String, Object> condition) throws Exception {
		// TODO Auto-generated method stub
		return gcmDao.insertDevice(condition);
	}

	@Override
	public int removeDevice(Map<String, Object> condition) throws Exception {
		// TODO Auto-generated method stub
		return gcmDao.deleteDevice(condition);
	}

	@Override
	public List<Gcm> sendMsg(Gcm gcmObj, boolean scheduleFlag) throws Exception {
		// TODO Auto-generated method stub
		
		List<Gcm> result = new Vector<Gcm>();
		/*
		mApiKey : api console 의 api 키 값
		message : 보낼 message 이며, Message.Builer() 에서 addData를 통해서 key velue 를 넣을수 있다.
		devices : push reg id 의 list
		*/
		String myApiKey = messages.getMessage("gcm.api.key");
		
		Map<String, Object> condition = new HashMap<String, Object>();
		
		//gcm 목록
		condition.put("status", 1);//발송 대기 상태
		condition.put("scheduleFlag", scheduleFlag);//스케줄 발송 여부. 스케줄 발송일 경우 now() > sendtime 인 목록만 발송한다.
		List<Gcm> gcmList = findbyList(condition);
		
		//gcm device 목록
		List<String> devices = (List<String>)findbyListDevice(condition);
		
		Sender sender = new Sender(myApiKey);
		Builder builder = new Message.Builder();

		//gcm data
		for(Gcm gcm : gcmList){
			int idx = gcm.getIdx();
			String title = gcm.getTitle();
			
			condition.put("gcmIdx", idx);
			List<Map<String, Object>> gcmDataList = findbyListData(condition);
			builder.addData("idx", Integer.toString(idx));
			builder.addData("title", URLEncoder.encode(title, "UTF-8"));
			for(Map<String, Object> gcmData : gcmDataList){
				String dataKey = URLEncoder.encode((String)gcmData.get("key"), "UTF-8");
				String data = URLEncoder.encode((String)gcmData.get("data"), "UTF-8");
				builder.addData(dataKey, data);
			}

			Message message = builder.build();
			MulticastResult mResult = sender.send(message, devices, 5);
			long successCnt = mResult.getSuccess();
			long failureCnt = mResult.getFailure();
			
			//성공, 실패 개수, 상태(발송 완료) 수정
			gcmObj.setIdx(gcm.getIdx());
			gcmObj.setSuccessCnt(successCnt);
			gcmObj.setFailureCnt(failureCnt);
			gcmObj.setStatus(2);
			modify(gcmObj);
			result.add(gcmObj);
		}
		
		return result;
	}

}